/********************************************************************
	created:	2012/03/26
	filename: 	Dx9FxMaterial.cpp
	author:		Mwolf
	
	purpose:	
*********************************************************************/

#include "Dx9FxMaterial.h"
#include "DX9Device.h"
#include "GWTypes.h"

#include <d3d9.h>
#include <d3dx9.h>
#include <assert.h>

static ID3DXEffectPool*		D3DXEffectPool = NULL;
static char*				ErrorString = NULL;
static ID3DXEffect*			DummyEffect = NULL;

static char DummyFxContent[] = {
	"shared float4x4		matView;\n"
	"shared float4x4		matProjection;\n"
	"shared float4x4		matViewProjection;\n"
	//"shared float4x4		matWorld;\n"
	//"shared float4x4		matWorldViewProjection;\n"
	"struct VS_OUTPUT\n"
	"{\n"
	"	float4	Position	: POSITION;\n"
	"};\n"

	"VS_OUTPUT DummyVS( float4 vPosition : POSITION )\n"
	"{\n"
	"	VS_OUTPUT Out = (VS_OUTPUT)0;\n"
	"	Out.Position = float4(1, 1, 1, 1);\n"
	"	return Out;\n"
	"}\n"

	"float4 DummyPS( VS_OUTPUT In ) : COLOR\n"
	"{\n"
	"	return float4(1, 1, 1, 1);\n"
	"}\n"

	"technique Default\n"
	"{\n"
	"	pass p0\n"
	"	{\n"
	"		VertexShader = compile vs_2_0 DummyVS();\n"
	"		PixelShader  = compile ps_2_0 DummyPS();\n"
	"	}\n"
	"}\n"
};

struct Dx9FXMaterial
{
	ID3DXEffect*	Effect;
};

static void Dx9FX_SetErrorString( const char* string );

bool Dx9FX_InitModule()
{
	assert( D3DXEffectPool == NULL );

	if ( FAILED( D3DXCreateEffectPool( &D3DXEffectPool ) ) )
		return false;

	LPD3DXBUFFER	pError;

	if ( FAILED( D3DXCreateEffect( D3DDevice(), DummyFxContent, strlen(DummyFxContent), NULL, NULL, NULL, 
		 D3DXEffectPool, &DummyEffect, &pError ) ) )
	{
		Dx9FX_SetErrorString( (const char*)pError->GetBufferPointer() );
	}

	return true;
}

void Dx9FX_DeinitModule()
{
	assert( D3DXEffectPool );
	SAFE_RELEASE( D3DXEffectPool );
}


static void Dx9FX_SetErrorString( const char* string )
{
	int len = strlen( string ) + 1;

	if ( ErrorString ) delete [] ErrorString;

	ErrorString = new char[len];
	memset( ErrorString, 0, len );

	strcpy( ErrorString, string );
}

const char* Dx9FX_GetLastErrorString()
{
	return ErrorString;
}

Dx9FXMaterial* Dx9FX_LoadEffectFromFile( const char* filename )
{
	assert( D3DXEffectPool );

	LPD3DXEFFECT	pEffect;
	LPD3DXBUFFER	pError;

	if ( FAILED( D3DXCreateEffectFromFileA( D3DDevice(), filename, NULL, NULL, NULL, 
		 D3DXEffectPool, &pEffect, &pError ) ) )
	{
		Dx9FX_SetErrorString( (const char*)pError->GetBufferPointer() );

		return NULL;
	}

	assert( pEffect );

	Dx9FXMaterial* fxMat = new Dx9FXMaterial();
	fxMat->Effect = pEffect;

	return fxMat;
}

void Dx9FX_UnloadEffect( Dx9FXMaterial* fxMat )
{
	SAFE_RELEASE( fxMat->Effect );
	delete fxMat;
}

ID3DXEffect* Dx9FX_GetD3DXEffect( Dx9FXMaterial* fxMat )
{
	return fxMat->Effect;
}

D3DXMATRIXA16 mViewProjection;

void Dx9FX_UpdateSharedMatrices( const D3DXMATRIX* pView, const D3DXMATRIX* pProj )
{
	mViewProjection = (*pView) * (*pProj);

	DummyEffect->SetMatrix( "matView",				pView );
	DummyEffect->SetMatrix( "matProjection",		pProj );
	DummyEffect->SetMatrix( "matViewProjection",	&mViewProjection );
}

void Dx9FX_UpdateNonSharedMatrices( Dx9FXMaterial* fxMat, D3DXMATRIX* pWorld )
{
	ID3DXEffect* pEffect = Dx9FX_GetD3DXEffect( fxMat );
	D3DXMATRIXA16 mWorldViewProjection = (*pWorld) * mViewProjection;

	pEffect->SetMatrix( "matWorld",					pWorld );
	pEffect->SetMatrix( "matWorldViewProjection",	&mWorldViewProjection );
}
